﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR;
using Microsoft.Owin.Hosting;
using Owin;
using System.Messaging;
using System.Threading;
using System.Diagnostics;
using Microsoft.Owin.Host.HttpListener;


namespace Derrick.Web
{
    public class MessagePump
    {
        private TraceSwitch _traceSwitch = new TraceSwitch("HTTP Stream Trace", "HTTP Stream Trace");

        public void Configuration(IAppBuilder app)
        {
            System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "Mapping the SignalR hubs now.");
            HubConfiguration config = new HubConfiguration();
            app.MapHubs();
            System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "SignalR hubs all mapped.");
        }
    }

    public class MessageHub : Hub
    {

        private TraceSwitch _traceSwitch = new TraceSwitch("HTTP Stream Trace", "HTTP Stream Trace");
        //private OwinHttpListener _signalRListener = null;

        public MessageHub()
            : base()
        {
            System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "MessageHub() instance instantiated.");

        }

        public void Configuration(IAppBuilder app)
        {
            System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "Mapping the SignalR hubs now.");
            HubConfiguration config = new HubConfiguration();
            //app.MapHubs();
            try
            {
                app.MapHubs();
            }
            catch (Exception ex)
            {
                System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "MessageHub::Configuration() Error: " + ex.ToString());
            }
            System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "SignalR hubs all mapped.");
        }

        public override Task OnReconnected()
        {
            System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "SignalR connection reconnected to MessageHub.");

            return base.OnReconnected();
        }

        public override Task OnDisconnected()
        {
            System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "SignalR connection disconnected from MessageHub.");

            return base.OnDisconnected();
        }

        public override Task OnConnected()
        {
            //BroadcastMessage();
            Task baseTask = null;

            try
            {
                baseTask = base.OnConnected();
                System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "SignalR connection received and connected.");
            }
            catch (Exception ex)
            {
                System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "OnConnected() throws exception: " + ex.ToString());
            }
            return baseTask;
        }


        public void Send(string message)
        {
            System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "MessageHub::SendMessage() called.");            
        }
    }

    public class Broadcaster : IDisposable
    {
        private System.Messaging.MessageQueue _messageQueue = null;
        private Thread _messageHandlingThread = null;
        private volatile bool _shutdown = false;
        private TraceSwitch _traceSwitch = new TraceSwitch("HTTP Stream Trace", "HTTP Stream Trace");
        private IHubContext _hubContext = null;

        public void BroadcastMessage()
        {

            System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "Broadcaster thread started.");

            while (!_shutdown)
            {
                System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "Broadcaster thread waiting for message.");
                Message msg = _messageQueue.Receive();
                System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "Broadcaster thread: message received.");
                msg.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) });
                System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "Broadcaster thread: message formatting...");
                string cometMsg = msg.Body.ToString();
                System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "Broadcaster thread: message converted to string: [" + cometMsg + "]");
                DateTime startTime = DateTime.Now;
                _hubContext.Clients.All.addMessage(cometMsg);
                DateTime endTime = DateTime.Now;
                System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "Broadcasting message took " + endTime.Subtract(startTime).TotalMilliseconds + " ms.");

            }

            System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "_shutdown variable set to true and detected.");

        }

        public Broadcaster()
        {
            string messageQueueName = ConfigurationManager.AppSettings["MessageQueue"];
            System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "Monitoring message queue: " + messageQueueName);
            _hubContext = GlobalHost.ConnectionManager.GetHubContext<MessageHub>();
            System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "Retrieved instance of SignalR hub.");
            _messageQueue = new MessageQueue(messageQueueName);
            System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "Message queue instantiated.");

            _messageHandlingThread = new Thread(new ThreadStart(BroadcastMessage));
            System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "Starting thread to monitor message queue.");
            _messageHandlingThread.Start();


        }

        public void Dispose()
        {
            _shutdown = true;
            System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "_shutdown variable set to true.");
            if (_messageHandlingThread != null)
            {
                System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "Aborting message pump thread.");
                _messageHandlingThread.Abort();
                System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "Message pump thread aborted.");
            }
            System.Diagnostics.Trace.WriteLineIf(_traceSwitch.TraceVerbose, "Exiting Broadcast class dispose method.");

        }

    }



}
